home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectSound / Play3DSound / play3dsound.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  31KB  |  824 lines

  1. //----------------------------------------------------------------------------
  2. // File: Play3DSound.cpp
  3. //
  4. // Desc: Main application file for the Play3DSound sample. This sample shows how
  5. //       to load a wave file and play it using a 3D DirectSound buffer.
  6. //
  7. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <commctrl.h>
  13. #include <commdlg.h>
  14. #include <mmreg.h>
  15. #include <mmsystem.h>
  16. #include <dxerr8.h>
  17. #include <dsound.h>
  18. #include <math.h>
  19. #include <stdio.h>
  20. #include "resource.h"
  21. #include "DSUtil.h"
  22. #include "DXUtil.h"
  23.  
  24.  
  25.  
  26. //-----------------------------------------------------------------------------
  27. // Function-prototypes
  28. //-----------------------------------------------------------------------------
  29. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  30. VOID    OnInitDialog( HWND hDlg );
  31. HRESULT InitDirectSound( HWND hDlg );
  32. HRESULT FreeDirectSound();
  33. VOID    SetSlidersPos( HWND hDlg, FLOAT fDopplerValue, FLOAT fRolloffValue, FLOAT fMinDistValue, FLOAT fMaxDistValue );
  34. VOID    OnOpenSoundFile( HWND hDlg );
  35. VOID    LoadWaveFileIntoBuffer( HWND hDlg, TCHAR* strFileName );
  36. INT_PTR CALLBACK AlgorithmDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  37. HRESULT OnPlaySound( HWND hDlg );
  38. VOID    OnSliderChanged( HWND hDlg );
  39. VOID    Set3DParameters( FLOAT fDopplerFactor, FLOAT fRolloffFactor, FLOAT fMinDistance,   FLOAT fMaxDistance );
  40. VOID    EnablePlayUI( HWND hDlg, BOOL bEnable );
  41. VOID    OnMovementTimer( HWND hDlg );
  42. VOID    UpdateGrid( HWND hDlg, FLOAT x, FLOAT y );
  43. VOID    SetObjectProperties( D3DVECTOR* pvPosition, D3DVECTOR* pvVelocity );
  44. FLOAT   ConvertLinearSliderPosToLogScale( LONG lSliderPos );
  45. LONG    ConvertLogScaleToLinearSliderPosTo( FLOAT fValue );
  46.  
  47.  
  48.  
  49.  
  50. //-----------------------------------------------------------------------------
  51. // Defines, constants, and global variables
  52. //-----------------------------------------------------------------------------
  53. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  54. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  55.  
  56. #define ORBIT_MAX_RADIUS        5.0f
  57. #define IDT_MOVEMENT_TIMER      1
  58.  
  59. CSoundManager*          g_pSoundManager       = NULL;
  60. CSound*                 g_pSound              = NULL;
  61. LPDIRECTSOUND3DBUFFER   g_pDS3DBuffer         = NULL;   // 3D sound buffer
  62. LPDIRECTSOUND3DLISTENER g_pDSListener         = NULL;   // 3D listener object
  63. DS3DBUFFER              g_dsBufferParams;               // 3D buffer properties
  64. DS3DLISTENER            g_dsListenerParams;             // Listener properties
  65. BOOL                    g_bDeferSettings      = FALSE;
  66. BOOL                    g_bAllowMovementTimer = TRUE;
  67.  
  68.  
  69.  
  70.  
  71. //-----------------------------------------------------------------------------
  72. // Name: WinMain()
  73. // Desc: Entry point for the application.  Since we use a simple dialog for 
  74. //       user interaction we don't need to pump messages.
  75. //-----------------------------------------------------------------------------
  76. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  77.                       INT nCmdShow )
  78. {
  79.     // Init the common control dll 
  80.     InitCommonControls();
  81.  
  82.     // Display the main dialog box.
  83.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
  84.  
  85.     return TRUE;
  86. }
  87.  
  88.  
  89.  
  90.  
  91. //-----------------------------------------------------------------------------
  92. // Name: MainDlgProc()
  93. // Desc: Handles dialog messages
  94. //-----------------------------------------------------------------------------
  95. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  96. {
  97.     HRESULT hr;
  98.  
  99.     switch( msg ) 
  100.     {
  101.         case WM_INITDIALOG:
  102.             OnInitDialog( hDlg );
  103.             break;
  104.  
  105.         case WM_COMMAND:
  106.             switch( LOWORD(wParam) )
  107.             {
  108.                 case IDC_SOUNDFILE:
  109.                     OnOpenSoundFile( hDlg );
  110.                     break;
  111.  
  112.                 case IDCANCEL:
  113.                     EndDialog( hDlg, IDCANCEL );
  114.                     break;
  115.  
  116.                 case IDC_PLAY:
  117.                     if( FAILED( hr = OnPlaySound( hDlg ) ) )
  118.                     {
  119.                         DXTRACE_ERR( TEXT("OnPlaySound"), hr );
  120.                         MessageBox( hDlg, "Error playing DirectSound buffer."
  121.                                     "Sample will now exit.", "DirectSound Sample", 
  122.                                     MB_OK | MB_ICONERROR );
  123.                         EndDialog( hDlg, IDABORT );
  124.                     }
  125.                     break;
  126.  
  127.                 case IDC_STOP:
  128.                     if( g_pSound )
  129.                     {
  130.                         g_pSound->Stop();
  131.                         g_pSound->Reset();
  132.                     }
  133.  
  134.                     // Update the UI controls to show the sound as stopped
  135.                     EnablePlayUI( hDlg, TRUE );
  136.                     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Sound stopped.") );
  137.                     break;
  138.  
  139.                 case IDC_DEFER:
  140.                     g_bDeferSettings = !g_bDeferSettings;
  141.                     OnSliderChanged( hDlg );                    
  142.                     break;
  143.  
  144.                 case IDC_APPLY:
  145.                     // Call the IDirectSound3DListener::CommitDeferredSettings 
  146.                     // method to execute all of the deferred commands at once.
  147.                     // This is many times more efficent than recomputing everything
  148.                     // for every call.
  149.                     if( g_pDSListener )
  150.                         g_pDSListener->CommitDeferredSettings();
  151.                     break;
  152.  
  153.                 default:
  154.                     return FALSE; // Didn't handle message
  155.             }
  156.             break;
  157.  
  158.         case WM_TIMER:
  159.             if( wParam == IDT_MOVEMENT_TIMER )
  160.                 OnMovementTimer( hDlg );
  161.             break;
  162.  
  163.         case WM_NOTIFY:
  164.             OnSliderChanged( hDlg );
  165.             break;
  166.  
  167.         case WM_DESTROY:
  168.             // Cleanup everything
  169.             KillTimer( hDlg, 1 );    
  170.             SAFE_RELEASE( g_pDSListener );
  171.             SAFE_RELEASE( g_pDS3DBuffer );
  172.  
  173.             SAFE_DELETE( g_pSound );
  174.             SAFE_DELETE( g_pSoundManager );
  175.             break; 
  176.             
  177.         default:
  178.             return FALSE; // Didn't handle message
  179.     }
  180.  
  181.     return TRUE; // Handled message
  182. }
  183.  
  184.  
  185.  
  186.  
  187. //-----------------------------------------------------------------------------
  188. // Name: OnInitDialog()
  189. // Desc: Initializes the dialogs (sets up UI controls, etc.)
  190. //-----------------------------------------------------------------------------
  191. VOID OnInitDialog( HWND hDlg )
  192. {
  193.     HRESULT hr;
  194.  
  195.     // Load the icon
  196. #ifdef _WIN64
  197.     HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
  198. #else
  199.     HINSTANCE hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
  200. #endif
  201.     HICON hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDR_MAINFRAME ) );
  202.  
  203.     // Create a static IDirectSound in the CSound class.  
  204.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  205.     // format to stereo, 22kHz and 16-bit output.
  206.     g_pSoundManager = new CSoundManager();
  207.  
  208.     hr = g_pSoundManager->Initialize( hDlg, DSSCL_PRIORITY, 2, 22050, 16 );
  209.  
  210.     // Get the 3D listener, so we can control its params
  211.     hr |= g_pSoundManager->Get3DListenerInterface( &g_pDSListener );
  212.  
  213.     if( FAILED(hr) )
  214.     {
  215.         DXTRACE_ERR( TEXT("Get3DListenerInterface"), hr );
  216.         MessageBox( hDlg, "Error initializing DirectSound.  Sample will now exit.", 
  217.                             "DirectSound Sample", MB_OK | MB_ICONERROR );
  218.         EndDialog( hDlg, IDABORT );
  219.         return;
  220.     }
  221.  
  222.     // Get listener parameters
  223.     g_dsListenerParams.dwSize = sizeof(DS3DLISTENER);
  224.     g_pDSListener->GetAllParameters( &g_dsListenerParams );
  225.  
  226.     // Set the icon for this dialog.
  227.     PostMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  228.     PostMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  229.  
  230.     // Create a timer to periodically move the 3D object around
  231.     SetTimer( hDlg, IDT_MOVEMENT_TIMER, 0, NULL );
  232.  
  233.     // Set the UI controls
  234.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  235.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("No file loaded.") );
  236.  
  237.     // Get handles to dialog items
  238.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  239.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  240.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  241.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  242.     HWND hVertSlider     = GetDlgItem( hDlg, IDC_VERTICAL_SLIDER );
  243.     HWND hHorzSlider     = GetDlgItem( hDlg, IDC_HORIZONTAL_SLIDER );
  244.  
  245.     // Set the range and position of the sliders
  246.     PostMessage( hDopplerSlider, TBM_SETRANGEMAX, TRUE, 40L );
  247.     PostMessage( hDopplerSlider, TBM_SETRANGEMIN, TRUE, 0L );
  248.  
  249.     PostMessage( hRolloffSlider, TBM_SETRANGEMAX, TRUE, 40L );
  250.     PostMessage( hRolloffSlider, TBM_SETRANGEMIN, TRUE, 0L );
  251.  
  252.     PostMessage( hMinDistSlider, TBM_SETRANGEMAX, TRUE, 40L );
  253.     PostMessage( hMinDistSlider, TBM_SETRANGEMIN, TRUE, 1L );
  254.  
  255.     PostMessage( hMaxDistSlider, TBM_SETRANGEMAX, TRUE, 40L );
  256.     PostMessage( hMaxDistSlider, TBM_SETRANGEMIN, TRUE, 1L );
  257.  
  258.     PostMessage( hVertSlider,    TBM_SETRANGEMAX, TRUE, 100L );
  259.     PostMessage( hVertSlider,    TBM_SETRANGEMIN, TRUE, -100L );
  260.     PostMessage( hVertSlider,    TBM_SETPOS,      TRUE, 100L );
  261.  
  262.     PostMessage( hHorzSlider,    TBM_SETRANGEMAX, TRUE, 100L );
  263.     PostMessage( hHorzSlider,    TBM_SETRANGEMIN, TRUE, -100L );
  264.     PostMessage( hHorzSlider,    TBM_SETPOS,      TRUE, 100L );
  265.  
  266.     // Set the position of the sliders
  267.     SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f );
  268. }
  269.  
  270.  
  271.  
  272.  
  273. //-----------------------------------------------------------------------------
  274. // Name: SetSlidersPos()
  275. // Desc: Sets the slider positions
  276. //-----------------------------------------------------------------------------
  277. VOID SetSlidersPos( HWND hDlg, FLOAT fDopplerValue, FLOAT fRolloffValue,
  278.                     FLOAT fMinDistValue, FLOAT fMaxDistValue )
  279. {
  280.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  281.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  282.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  283.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  284.  
  285.     LONG lDopplerSlider = ConvertLogScaleToLinearSliderPosTo( fDopplerValue );
  286.     LONG lRolloffSlider = ConvertLogScaleToLinearSliderPosTo( fRolloffValue );
  287.     LONG lMinDistSlider = ConvertLogScaleToLinearSliderPosTo( fMinDistValue );
  288.     LONG lMaxDistSlider = ConvertLogScaleToLinearSliderPosTo( fMaxDistValue );
  289.  
  290.     PostMessage( hDopplerSlider, TBM_SETPOS, TRUE, lDopplerSlider );
  291.     PostMessage( hRolloffSlider, TBM_SETPOS, TRUE, lRolloffSlider );
  292.     PostMessage( hMinDistSlider, TBM_SETPOS, TRUE, lMinDistSlider );
  293.     PostMessage( hMaxDistSlider, TBM_SETPOS, TRUE, lMaxDistSlider );
  294. }
  295.  
  296.  
  297.  
  298.  
  299. //-----------------------------------------------------------------------------
  300. // Name: OnOpenSoundFile()
  301. // Desc: Called when the user requests to open a sound file
  302. //-----------------------------------------------------------------------------
  303. VOID OnOpenSoundFile( HWND hDlg ) 
  304. {
  305.     GUID    guid3DAlgorithm = GUID_NULL;
  306.     int     nResult;
  307.     HRESULT hr; 
  308.  
  309.     static TCHAR strFileName[MAX_PATH] = TEXT("");
  310.     static TCHAR strPath[MAX_PATH] = TEXT("");
  311.  
  312.     // Setup the OPENFILENAME structure
  313.     OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL,
  314.                          TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL,
  315.                          0, 1, strFileName, MAX_PATH, NULL, 0, strPath,
  316.                          TEXT("Open Sound File"),
  317.                          OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0,
  318.                          TEXT(".wav"), 0, NULL, NULL };
  319.  
  320.     // Get the default media path (something like C:\WINDOWS\MEDIA)
  321.     if( '\0' == strPath[0] )
  322.     {
  323.         GetWindowsDirectory( strPath, MAX_PATH );
  324.         if( strcmp( &strPath[strlen(strPath)], TEXT("\\") ) )
  325.             strcat( strPath, TEXT("\\") );
  326.         strcat( strPath, TEXT("MEDIA") );
  327.     }
  328.  
  329.     if( g_pSound )
  330.     {
  331.         g_pSound->Stop();
  332.         g_pSound->Reset();
  333.     }
  334.  
  335.     // Update the UI controls to show the sound as loading a file
  336.     EnableWindow( GetDlgItem( hDlg, IDC_PLAY ), FALSE);
  337.     EnableWindow( GetDlgItem( hDlg, IDC_STOP ), FALSE);
  338.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Loading file...") );
  339.  
  340.     // Stop the timer while dialogs are displayed
  341.     g_bAllowMovementTimer = FALSE;
  342.  
  343.     // Display the OpenFileName dialog. Then, try to load the specified file
  344.     if( TRUE != GetOpenFileName( &ofn ) )
  345.     {
  346.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") );
  347.         g_bAllowMovementTimer = TRUE;
  348.         return;
  349.     }
  350.  
  351.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  352.  
  353.     // Free any previous sound, and make a new one
  354.     SAFE_DELETE( g_pSound );
  355.  
  356.     CWaveFile waveFile;
  357.     waveFile.Open( strFileName, NULL, WAVEFILE_READ );
  358.     WAVEFORMATEX* pwfx = waveFile.GetFormat();
  359.     if( pwfx == NULL )
  360.     {
  361.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Invalid wave file format.") );
  362.         return;
  363.     }
  364.  
  365.     if( pwfx->nChannels > 1 )
  366.     {
  367.         // Too many channels in wave.  Sound must be mono when using DSBCAPS_CTRL3D
  368.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be mono for 3D control.") );
  369.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  370.         return;
  371.     }
  372.  
  373.     if( pwfx->wFormatTag != WAVE_FORMAT_PCM )
  374.     {
  375.         // Sound must be PCM when using DSBCAPS_CTRL3D
  376.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be PCM for 3D control.") );
  377.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  378.         return;
  379.     }
  380.  
  381.     // Get the software DirectSound3D emulation algorithm to use
  382.     // Ask the user for this sample, so display the algorithm dialog box.
  383.     nResult = (int)DialogBox( NULL, MAKEINTRESOURCE(IDD_3D_ALGORITHM), 
  384.                               NULL, AlgorithmDlgProc );
  385.     switch( nResult )
  386.     {
  387.     case -1: // User canceled dialog box
  388.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") );
  389.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  390.         return;
  391.  
  392.     case 0: // User selected DS3DALG_NO_VIRTUALIZATION  
  393.         guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
  394.         break;
  395.  
  396.     case 1: // User selected DS3DALG_HRTF_FULL  
  397.         guid3DAlgorithm = DS3DALG_HRTF_FULL;
  398.         break;
  399.  
  400.     case 2: // User selected DS3DALG_HRTF_LIGHT
  401.         guid3DAlgorithm = DS3DALG_HRTF_LIGHT;
  402.         break;
  403.     }
  404.  
  405.     // Load the wave file into a DirectSound buffer
  406.     hr = g_pSoundManager->Create( &g_pSound, strFileName, DSBCAPS_CTRL3D, guid3DAlgorithm );  
  407.     if( FAILED( hr ) || hr == DS_NO_VIRTUALIZATION )
  408.     {
  409.         DXTRACE_ERR_NOMSGBOX( TEXT("Create"), hr );
  410.         if( DS_NO_VIRTUALIZATION == hr )
  411.         {
  412.             MessageBox( hDlg, "The 3D virtualization algorithm requested is not supported under this "
  413.                         "operating system.  It is available only on Windows 2000, Windows ME, and Windows 98 with WDM "
  414.                         "drivers and beyond.  Creating buffer with no virtualization.", 
  415.                         "DirectSound Sample", MB_OK );
  416.         }
  417.  
  418.         // Unknown error, but not a critical failure, so just update the status
  419.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Could not create sound buffer.") );
  420.         return; 
  421.     }
  422.  
  423.     // Get the 3D buffer from the secondary buffer
  424.     if( FAILED( hr = g_pSound->Get3DBufferInterface( 0, &g_pDS3DBuffer ) ) )
  425.     {
  426.         DXTRACE_ERR( TEXT("Get3DBufferInterface"), hr );
  427.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not get 3D buffer.") );
  428.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  429.         return;
  430.     }
  431.  
  432.     // Get the 3D buffer parameters
  433.     g_dsBufferParams.dwSize = sizeof(DS3DBUFFER);
  434.     g_pDS3DBuffer->GetAllParameters( &g_dsBufferParams );
  435.  
  436.     // Set new 3D buffer parameters
  437.     g_dsBufferParams.dwMode = DS3DMODE_HEADRELATIVE;
  438.     g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE );
  439.  
  440.     DSBCAPS dsbcaps;
  441.     ZeroMemory( &dsbcaps, sizeof(DSBCAPS) );
  442.     dsbcaps.dwSize = sizeof(DSBCAPS);
  443.  
  444.     LPDIRECTSOUNDBUFFER pDSB = g_pSound->GetBuffer( 0 );
  445.     pDSB->GetCaps( &dsbcaps );
  446.     if( ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) != 0 )
  447.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using hardware mixing.") );
  448.     else
  449.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using software mixing.") );
  450.  
  451.     // Update the UI controls to show the sound as the file is loaded
  452.     SetDlgItemText( hDlg, IDC_FILENAME, strFileName );
  453.     EnablePlayUI( hDlg, TRUE );
  454.  
  455.     g_bAllowMovementTimer = TRUE;
  456.  
  457.     // Remember the path for next time
  458.     strcpy( strPath, strFileName );
  459.     char* strLastSlash = strrchr( strPath, '\\' );
  460.     strLastSlash[0] = '\0';
  461.  
  462.     // Set the slider positions
  463.     SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f );
  464.     OnSliderChanged( hDlg );
  465. }
  466.  
  467.  
  468.  
  469.  
  470. //-----------------------------------------------------------------------------
  471. // Name: AlgorithmDlgProc()
  472. // Desc: Handles dialog messages
  473. //-----------------------------------------------------------------------------
  474. INT_PTR CALLBACK AlgorithmDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  475. {
  476.     // Default is DS3DALG_NO_VIRTUALIZATION for fastest performance
  477.     static int nDefaultRadio = IDC_NO_VIRT_RADIO;
  478.  
  479.     switch( msg ) 
  480.     {
  481.         case WM_INITDIALOG:
  482.             // Default is DS3DALG_NO_VIRTUALIZATION for fastest performance
  483.             CheckRadioButton( hDlg, IDC_NO_VIRT_RADIO, IDC_LIGHT_VIRT_RADIO, nDefaultRadio );
  484.             return TRUE; // Message handled 
  485.  
  486.         case WM_COMMAND:
  487.             switch( LOWORD(wParam) )
  488.             {
  489.                 case IDCANCEL:
  490.                     EndDialog( hDlg, -1 );
  491.                     return TRUE; // Message handled 
  492.  
  493.                 case IDOK:
  494.                     if( IsDlgButtonChecked( hDlg, IDC_NO_VIRT_RADIO )    == BST_CHECKED )
  495.                     {
  496.                         nDefaultRadio = IDC_NO_VIRT_RADIO;
  497.                         EndDialog( hDlg, 0 );
  498.                     }
  499.  
  500.                     if( IsDlgButtonChecked( hDlg, IDC_HIGH_VIRT_RADIO )  == BST_CHECKED )
  501.                     {               
  502.                         nDefaultRadio = IDC_HIGH_VIRT_RADIO;
  503.                         EndDialog( hDlg, 1 );
  504.                     }
  505.  
  506.                     if( IsDlgButtonChecked( hDlg, IDC_LIGHT_VIRT_RADIO ) == BST_CHECKED )
  507.                     {               
  508.                         nDefaultRadio = IDC_LIGHT_VIRT_RADIO;
  509.                         EndDialog( hDlg, 2 );
  510.                     }
  511.                         
  512.                     return TRUE; // Message handled 
  513.             }
  514.             break;
  515.     }
  516.  
  517.     return FALSE; // Message not handled 
  518. }
  519.  
  520.  
  521.  
  522.  
  523. //-----------------------------------------------------------------------------
  524. // Name: OnPlaySound()
  525. // Desc: User hit the "Play" button
  526. //-----------------------------------------------------------------------------
  527. HRESULT OnPlaySound( HWND hDlg ) 
  528. {
  529.     HRESULT hr;
  530.  
  531.     if( NULL == g_pSound )
  532.         return E_FAIL;
  533.  
  534.     // Play buffer always in looped mode just for this sample
  535.     if( FAILED( hr = g_pSound->Play( 0, DSBPLAY_LOOPING ) ) )
  536.         return DXTRACE_ERR( TEXT("Play"), hr );
  537.  
  538.     // Update the UI controls to show the sound as playing
  539.     EnablePlayUI( hDlg, FALSE );
  540.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Sound playing.") );
  541.  
  542.     return S_OK;
  543. }
  544.  
  545.  
  546.  
  547.  
  548. //-----------------------------------------------------------------------------
  549. // Name: OnSliderChanged()  
  550. // Desc: Called when the dialog's slider bars are changed by the user, or need
  551. //       updating
  552. //-----------------------------------------------------------------------------
  553. VOID OnSliderChanged( HWND hDlg )
  554. {
  555.     TCHAR strBuffer[10];
  556.     FLOAT fDopplerFactor;
  557.     FLOAT fRolloffFactor;
  558.     FLOAT fMinDistance; 
  559.     FLOAT fMaxDistance;
  560.  
  561.     // Get handles to dialog items
  562.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  563.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  564.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  565.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  566.  
  567.     // Get the position of the sliders
  568.     fDopplerFactor = ConvertLinearSliderPosToLogScale( (long)SendMessage( hDopplerSlider, TBM_GETPOS, 0, 0 ) );
  569.     fRolloffFactor = ConvertLinearSliderPosToLogScale( (long)SendMessage( hRolloffSlider, TBM_GETPOS, 0, 0 ) );
  570.     fMinDistance   = ConvertLinearSliderPosToLogScale( (long)SendMessage( hMinDistSlider, TBM_GETPOS, 0, 0 ) );
  571.     fMaxDistance   = ConvertLinearSliderPosToLogScale( (long)SendMessage( hMaxDistSlider, TBM_GETPOS, 0, 0 ) );
  572.  
  573.     // Set the static text boxes
  574.     sprintf( strBuffer, TEXT("%.2f"), fDopplerFactor );
  575.     SetWindowText( GetDlgItem( hDlg, IDC_DOPPLERFACTOR ), strBuffer );
  576.  
  577.     sprintf( strBuffer, TEXT("%.2f"), fRolloffFactor );
  578.     SetWindowText( GetDlgItem( hDlg, IDC_ROLLOFFFACTOR ), strBuffer );
  579.  
  580.     sprintf( strBuffer, TEXT("%.2f"), fMinDistance );
  581.     SetWindowText( GetDlgItem( hDlg, IDC_MINDISTANCE ), strBuffer );
  582.  
  583.     sprintf( strBuffer, TEXT("%.2f"), fMaxDistance );
  584.     SetWindowText( GetDlgItem( hDlg, IDC_MAXDISTANCE ), strBuffer );
  585.  
  586.     // Set the options in the DirectSound buffer
  587.     Set3DParameters( fDopplerFactor, fRolloffFactor, fMinDistance, fMaxDistance );
  588.  
  589.     EnableWindow( GetDlgItem( hDlg, IDC_APPLY ), g_bDeferSettings );
  590. }
  591.  
  592.  
  593.  
  594.  
  595. //-----------------------------------------------------------------------------
  596. // Name: Set3DParameters()
  597. // Desc: Set the 3D buffer parameters
  598. //-----------------------------------------------------------------------------
  599. VOID Set3DParameters( FLOAT fDopplerFactor, FLOAT fRolloffFactor,
  600.                       FLOAT fMinDistance,   FLOAT fMaxDistance )
  601. {
  602.     // Every change to 3-D sound buffer and listener settings causes 
  603.     // DirectSound to remix, at the expense of CPU cycles. 
  604.     // To minimize the performance impact of changing 3-D settings, 
  605.     // use the DS3D_DEFERRED flag in the dwApply parameter of any of 
  606.     // the IDirectSound3DListener or IDirectSound3DBuffer methods that 
  607.     // change 3-D settings. Then call the IDirectSound3DListener::CommitDeferredSettings 
  608.     // method to execute all of the deferred commands at once.
  609.     DWORD dwApplyFlag = ( g_bDeferSettings ) ? DS3D_DEFERRED : DS3D_IMMEDIATE;
  610.  
  611.     g_dsListenerParams.flDopplerFactor = fDopplerFactor;
  612.     g_dsListenerParams.flRolloffFactor = fRolloffFactor;
  613.  
  614.     if( g_pDSListener )
  615.         g_pDSListener->SetAllParameters( &g_dsListenerParams, dwApplyFlag );
  616.  
  617.     g_dsBufferParams.flMinDistance = fMinDistance;
  618.     g_dsBufferParams.flMaxDistance = fMaxDistance;
  619.  
  620.     if( g_pDS3DBuffer )
  621.         g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, dwApplyFlag );
  622. }
  623.  
  624.  
  625.  
  626.  
  627. //-----------------------------------------------------------------------------
  628. // Name: EnablePlayUI()
  629. // Desc: Enables or disables the Play UI controls 
  630. //-----------------------------------------------------------------------------
  631. VOID EnablePlayUI( HWND hDlg, BOOL bEnable )
  632. {
  633.     if( bEnable )
  634.     {
  635.         EnableWindow(   GetDlgItem( hDlg, IDC_PLAY ),       TRUE );
  636.         EnableWindow(   GetDlgItem( hDlg, IDC_STOP ),       FALSE );
  637.         SetFocus(       GetDlgItem( hDlg, IDC_PLAY ) );
  638.     }
  639.     else
  640.     {
  641.         EnableWindow(  GetDlgItem( hDlg, IDC_PLAY ),       FALSE );
  642.         EnableWindow(  GetDlgItem( hDlg, IDC_STOP ),       TRUE );
  643.         SetFocus(      GetDlgItem( hDlg, IDC_STOP ) );
  644.     }
  645. }
  646.  
  647.  
  648.  
  649.  
  650. //-----------------------------------------------------------------------------
  651. // Name: OnMovementTimer()
  652. // Desc: Periodically updates the position of the object 
  653. //-----------------------------------------------------------------------------
  654. VOID OnMovementTimer( HWND hDlg ) 
  655. {
  656.     FLOAT fXScale;
  657.     FLOAT fYScale;
  658.  
  659.     if( !g_bAllowMovementTimer )
  660.         return;
  661.  
  662.     HWND hHorzSlider = GetDlgItem( hDlg, IDC_HORIZONTAL_SLIDER );
  663.     HWND hVertSlider = GetDlgItem( hDlg, IDC_VERTICAL_SLIDER );
  664.  
  665.     fXScale = SendMessage( hHorzSlider, TBM_GETPOS, 0, 0 ) / 100.0f;
  666.     fYScale = SendMessage( hVertSlider, TBM_GETPOS, 0, 0 ) / 100.0f;
  667.     FLOAT t = timeGetTime()/1000.0f;
  668.  
  669.     // Move the sound object around the listener. The maximum radius of the
  670.     // orbit is 27.5 units.
  671.     D3DVECTOR vPosition;
  672.     vPosition.x = ORBIT_MAX_RADIUS * fXScale * (FLOAT)sin(t);
  673.     vPosition.y = 0.0f;
  674.     vPosition.z = ORBIT_MAX_RADIUS * fYScale * (FLOAT)cos(t);
  675.  
  676.     D3DVECTOR vVelocity;
  677.     vVelocity.x = ORBIT_MAX_RADIUS * fXScale * (FLOAT)sin(t+0.05f);
  678.     vVelocity.y = 0.0f;
  679.     vVelocity.z = ORBIT_MAX_RADIUS * fYScale * (FLOAT)cos(t+0.05f);
  680.  
  681.     // Show the object's position on the dialog's grid control
  682.     UpdateGrid( hDlg, vPosition.x, vPosition.z );
  683.  
  684.     // Set the sound buffer velocity and position
  685.     SetObjectProperties( &vPosition, &vVelocity );
  686. }
  687.  
  688.  
  689.  
  690.  
  691. //-----------------------------------------------------------------------------
  692. // Name: UpdateGrid()
  693. // Desc: Draws a red dot in the dialog's grid bitmap at the x,y coordinate.
  694. //-----------------------------------------------------------------------------
  695. VOID UpdateGrid( HWND hDlg, FLOAT x, FLOAT y )
  696. {
  697.     static LONG s_lPixel[5] = { CLR_INVALID,CLR_INVALID,CLR_INVALID,CLR_INVALID,CLR_INVALID };
  698.     static LONG s_lX = 0;
  699.     static LONG s_lY = 0;
  700.  
  701.     HWND hWndGrid = GetDlgItem( hDlg, IDC_RENDER_WINDOW );
  702.     HDC  hDC      = GetDC( hWndGrid );
  703.     RECT rc;
  704.  
  705.     // Don't update the grid if a WM_PAINT will be called soon
  706.     BOOL bUpdateInProgress = GetUpdateRect(hDlg,NULL,FALSE);
  707.     if( bUpdateInProgress )
  708.         return;
  709.  
  710.     if( s_lPixel[0] != CLR_INVALID ) 
  711.     {
  712.         // Replace pixels from that were overdrawn last time
  713.         SetPixel( hDC, s_lX-1, s_lY+0, s_lPixel[0] );
  714.         SetPixel( hDC, s_lX+0, s_lY-1, s_lPixel[1] );
  715.         SetPixel( hDC, s_lX+0, s_lY+0, s_lPixel[2] );
  716.         SetPixel( hDC, s_lX+0, s_lY+1, s_lPixel[3] );
  717.         SetPixel( hDC, s_lX+1, s_lY+0, s_lPixel[4] );   
  718.     }
  719.  
  720.     // Convert the world space x,y coordinates to pixel coordinates
  721.     GetClientRect( hWndGrid, &rc );
  722.     s_lX = (LONG)( ( x/ORBIT_MAX_RADIUS + 1 ) * ( rc.left + rc.right ) / 2 );
  723.     s_lY = (LONG)( (-y/ORBIT_MAX_RADIUS + 1 ) * ( rc.top + rc.bottom ) / 2 );
  724.  
  725.     // Save the pixels before drawing the cross hair
  726.     s_lPixel[0] = GetPixel( hDC, s_lX-1, s_lY+0 );
  727.     s_lPixel[1] = GetPixel( hDC, s_lX+0, s_lY-1 );
  728.     s_lPixel[2] = GetPixel( hDC, s_lX+0, s_lY+0 );
  729.     s_lPixel[3] = GetPixel( hDC, s_lX+0, s_lY+1 );
  730.     s_lPixel[4] = GetPixel( hDC, s_lX+1, s_lY+0 );
  731.  
  732.     // Draw a crosshair object in red pixels
  733.     SetPixel( hDC, s_lX-1, s_lY+0, 0x000000ff );
  734.     SetPixel( hDC, s_lX+0, s_lY-1, 0x000000ff );
  735.     SetPixel( hDC, s_lX+0, s_lY+0, 0x000000ff );
  736.     SetPixel( hDC, s_lX+0, s_lY+1, 0x000000ff );
  737.     SetPixel( hDC, s_lX+1, s_lY+0, 0x000000ff );
  738.  
  739.     ReleaseDC( hWndGrid, hDC );
  740. }
  741.  
  742.  
  743.  
  744.  
  745. //-----------------------------------------------------------------------------
  746. // Name: SetObjectProperties()
  747. // Desc: Sets the position and velocity on the 3D buffer
  748. //-----------------------------------------------------------------------------
  749. VOID SetObjectProperties( D3DVECTOR* pvPosition, D3DVECTOR* pvVelocity )
  750. {
  751.     // Every change to 3-D sound buffer and listener settings causes 
  752.     // DirectSound to remix, at the expense of CPU cycles. 
  753.     // To minimize the performance impact of changing 3-D settings, 
  754.     // use the DS3D_DEFERRED flag in the dwApply parameter of any of 
  755.     // the IDirectSound3DListener or IDirectSound3DBuffer methods that 
  756.     // change 3-D settings. Then call the IDirectSound3DListener::CommitDeferredSettings 
  757.     // method to execute all of the deferred commands at once.
  758.     memcpy( &g_dsBufferParams.vPosition, pvPosition, sizeof(D3DVECTOR) );
  759.     memcpy( &g_dsBufferParams.vVelocity, pvVelocity, sizeof(D3DVECTOR) );
  760.  
  761.     if( g_pDS3DBuffer )
  762.         g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE );
  763. }
  764.  
  765.  
  766.  
  767.  
  768. //-----------------------------------------------------------------------------
  769. // Name: ConvertLinearSliderPosToLogScale()
  770. // Desc: Converts a linear slider position to a quasi logrithmic scale
  771. //-----------------------------------------------------------------------------
  772. FLOAT ConvertLinearSliderPosToLogScale( LONG lSliderPos )
  773. {
  774.     if( lSliderPos > 0 && lSliderPos <= 10 )
  775.     {
  776.         return lSliderPos*0.01f;
  777.     }
  778.     else if( lSliderPos > 10 && lSliderPos <= 20 )
  779.     {
  780.         return (lSliderPos-10)*0.1f;
  781.     }
  782.     else if( lSliderPos > 20 && lSliderPos <= 30 )
  783.     {
  784.         return (lSliderPos-20)*1.0f;
  785.     }
  786.     else if( lSliderPos > 30 && lSliderPos <= 40 )
  787.     {
  788.         return (lSliderPos-30)*10.0f;
  789.     }
  790.  
  791.     return 0.0f;
  792. }
  793.  
  794.  
  795.  
  796.  
  797. //-----------------------------------------------------------------------------
  798. // Name: ConvertLinearSliderPosToLogScale()
  799. // Desc: Converts a quasi logrithmic scale to a slider position
  800. //-----------------------------------------------------------------------------
  801. LONG ConvertLogScaleToLinearSliderPosTo( FLOAT fValue )
  802. {
  803.     if( fValue > 0.0f && fValue <= 0.1f )
  804.     {
  805.         return (LONG)(fValue/0.01f);
  806.     }
  807.     else if( fValue > 0.1f && fValue <= 1.0f )
  808.     {
  809.         return (LONG)(fValue/0.1f) + 10;
  810.     }
  811.     else if( fValue > 1.0f && fValue <= 10.0f )
  812.     {
  813.         return (LONG)(fValue/1.0f) + 20;
  814.     }
  815.     else if( fValue > 10.0f && fValue <= 100.0f )
  816.     {
  817.         return (LONG)(fValue/10.0f) + 30;
  818.     }
  819.  
  820.     return 0;
  821. }
  822.  
  823.  
  824.